package cn.jingyuan.swan.gw.web.config;

import cn.jingyuan.swan.cloud.oauth2.DefaultOAuth2Helper;
import cn.jingyuan.swan.cloud.oauth2.DefaultOAuth2ResourceDetails;
import cn.jingyuan.swan.cloud.oauth2.client.DefaultOAuth2ClientProperties;
import cn.jingyuan.swan.cloud.oauth2.error.DefaultOAuth2AccessDeniedHandler;
import cn.jingyuan.swan.cloud.oauth2.error.DefaultOAuth2AuthenticationEntryPoint;
import cn.jingyuan.swan.gw.manager.AccessCheckManager;
import cn.jingyuan.swan.gw.web.filter.AccessCheckFilter;
import cn.jingyuan.swan.gw.web.filter.HeaderFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

import javax.annotation.Resource;

/**
 * 资源服务器配置
 */
@Slf4j
@Configuration
@EnableResourceServer
@EnableConfigurationProperties({DefaultOAuth2ResourceDetails.class, DefaultOAuth2ClientProperties.class})
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Resource
    AccessDeniedHandler accessDeniedHandler;

    @Resource
    AuthenticationEntryPoint authenticationEntryPoint;

    @Resource
    AccessCheckManager accessCheckManager;

    @Resource
    DefaultOAuth2ResourceDetails oAuth2ResourceDetails;

    @Resource
    OAuth2WebSecurityExpressionHandler securityExpressionHandler;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources
            .tokenServices(DefaultOAuth2Helper.buildUserInfoTokenServices(oAuth2ResourceDetails))
            .expressionHandler(securityExpressionHandler);

        resources
            .accessDeniedHandler(new DefaultOAuth2AccessDeniedHandler())
            .authenticationEntryPoint(new DefaultOAuth2AuthenticationEntryPoint());
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf()
            .disable();

        http.cors()
            .disable();

        http.sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);

        http.exceptionHandling()
            .accessDeniedHandler(accessDeniedHandler)
            .authenticationEntryPoint(authenticationEntryPoint);

        http
            .addFilterBefore(new HeaderFilter(), AbstractPreAuthenticatedProcessingFilter.class)
            .addFilterAfter(new AccessCheckFilter(accessCheckManager, accessDeniedHandler), AbstractPreAuthenticatedProcessingFilter.class);

        http.authorizeRequests()
            // 指定监控可访问权限
            .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()

            // 动态权限验证
            .anyRequest().access("@accessCheckManager.accessChecking(request,authentication)");

    }

}

